{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Integers - Constructors and Bases"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Constructors"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The ``int`` class has two constructors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on class int in module builtins:\n",
      "\n",
      "class int(object)\n",
      " |  int(x=0) -> integer\n",
      " |  int(x, base=10) -> integer\n",
      " |  \n",
      " |  Convert a number or string to an integer, or return 0 if no arguments\n",
      " |  are given.  If x is a number, return x.__int__().  For floating point\n",
      " |  numbers, this truncates towards zero.\n",
      " |  \n",
      " |  If x is not a number or if base is given, then x must be a string,\n",
      " |  bytes, or bytearray instance representing an integer literal in the\n",
      " |  given base.  The literal can be preceded by '+' or '-' and be surrounded\n",
      " |  by whitespace.  The base defaults to 10.  Valid bases are 0 and 2-36.\n",
      " |  Base 0 means to interpret the base from the string as an integer literal.\n",
      " |  >>> int('0b100', base=0)\n",
      " |  4\n",
      " |  \n",
      " |  Methods defined here:\n",
      " |  \n",
      " |  __abs__(self, /)\n",
      " |      abs(self)\n",
      " |  \n",
      " |  __add__(self, value, /)\n",
      " |      Return self+value.\n",
      " |  \n",
      " |  __and__(self, value, /)\n",
      " |      Return self&value.\n",
      " |  \n",
      " |  __bool__(self, /)\n",
      " |      self != 0\n",
      " |  \n",
      " |  __ceil__(...)\n",
      " |      Ceiling of an Integral returns itself.\n",
      " |  \n",
      " |  __divmod__(self, value, /)\n",
      " |      Return divmod(self, value).\n",
      " |  \n",
      " |  __eq__(self, value, /)\n",
      " |      Return self==value.\n",
      " |  \n",
      " |  __float__(self, /)\n",
      " |      float(self)\n",
      " |  \n",
      " |  __floor__(...)\n",
      " |      Flooring an Integral returns itself.\n",
      " |  \n",
      " |  __floordiv__(self, value, /)\n",
      " |      Return self//value.\n",
      " |  \n",
      " |  __format__(...)\n",
      " |      default object formatter\n",
      " |  \n",
      " |  __ge__(self, value, /)\n",
      " |      Return self>=value.\n",
      " |  \n",
      " |  __getattribute__(self, name, /)\n",
      " |      Return getattr(self, name).\n",
      " |  \n",
      " |  __getnewargs__(...)\n",
      " |  \n",
      " |  __gt__(self, value, /)\n",
      " |      Return self>value.\n",
      " |  \n",
      " |  __hash__(self, /)\n",
      " |      Return hash(self).\n",
      " |  \n",
      " |  __index__(self, /)\n",
      " |      Return self converted to an integer, if self is suitable for use as an index into a list.\n",
      " |  \n",
      " |  __int__(self, /)\n",
      " |      int(self)\n",
      " |  \n",
      " |  __invert__(self, /)\n",
      " |      ~self\n",
      " |  \n",
      " |  __le__(self, value, /)\n",
      " |      Return self<=value.\n",
      " |  \n",
      " |  __lshift__(self, value, /)\n",
      " |      Return self<<value.\n",
      " |  \n",
      " |  __lt__(self, value, /)\n",
      " |      Return self<value.\n",
      " |  \n",
      " |  __mod__(self, value, /)\n",
      " |      Return self%value.\n",
      " |  \n",
      " |  __mul__(self, value, /)\n",
      " |      Return self*value.\n",
      " |  \n",
      " |  __ne__(self, value, /)\n",
      " |      Return self!=value.\n",
      " |  \n",
      " |  __neg__(self, /)\n",
      " |      -self\n",
      " |  \n",
      " |  __new__(*args, **kwargs) from builtins.type\n",
      " |      Create and return a new object.  See help(type) for accurate signature.\n",
      " |  \n",
      " |  __or__(self, value, /)\n",
      " |      Return self|value.\n",
      " |  \n",
      " |  __pos__(self, /)\n",
      " |      +self\n",
      " |  \n",
      " |  __pow__(self, value, mod=None, /)\n",
      " |      Return pow(self, value, mod).\n",
      " |  \n",
      " |  __radd__(self, value, /)\n",
      " |      Return value+self.\n",
      " |  \n",
      " |  __rand__(self, value, /)\n",
      " |      Return value&self.\n",
      " |  \n",
      " |  __rdivmod__(self, value, /)\n",
      " |      Return divmod(value, self).\n",
      " |  \n",
      " |  __repr__(self, /)\n",
      " |      Return repr(self).\n",
      " |  \n",
      " |  __rfloordiv__(self, value, /)\n",
      " |      Return value//self.\n",
      " |  \n",
      " |  __rlshift__(self, value, /)\n",
      " |      Return value<<self.\n",
      " |  \n",
      " |  __rmod__(self, value, /)\n",
      " |      Return value%self.\n",
      " |  \n",
      " |  __rmul__(self, value, /)\n",
      " |      Return value*self.\n",
      " |  \n",
      " |  __ror__(self, value, /)\n",
      " |      Return value|self.\n",
      " |  \n",
      " |  __round__(...)\n",
      " |      Rounding an Integral returns itself.\n",
      " |      Rounding with an ndigits argument also returns an integer.\n",
      " |  \n",
      " |  __rpow__(self, value, mod=None, /)\n",
      " |      Return pow(value, self, mod).\n",
      " |  \n",
      " |  __rrshift__(self, value, /)\n",
      " |      Return value>>self.\n",
      " |  \n",
      " |  __rshift__(self, value, /)\n",
      " |      Return self>>value.\n",
      " |  \n",
      " |  __rsub__(self, value, /)\n",
      " |      Return value-self.\n",
      " |  \n",
      " |  __rtruediv__(self, value, /)\n",
      " |      Return value/self.\n",
      " |  \n",
      " |  __rxor__(self, value, /)\n",
      " |      Return value^self.\n",
      " |  \n",
      " |  __sizeof__(...)\n",
      " |      Returns size in memory, in bytes\n",
      " |  \n",
      " |  __str__(self, /)\n",
      " |      Return str(self).\n",
      " |  \n",
      " |  __sub__(self, value, /)\n",
      " |      Return self-value.\n",
      " |  \n",
      " |  __truediv__(self, value, /)\n",
      " |      Return self/value.\n",
      " |  \n",
      " |  __trunc__(...)\n",
      " |      Truncating an Integral returns itself.\n",
      " |  \n",
      " |  __xor__(self, value, /)\n",
      " |      Return self^value.\n",
      " |  \n",
      " |  bit_length(...)\n",
      " |      int.bit_length() -> int\n",
      " |      \n",
      " |      Number of bits necessary to represent self in binary.\n",
      " |      >>> bin(37)\n",
      " |      '0b100101'\n",
      " |      >>> (37).bit_length()\n",
      " |      6\n",
      " |  \n",
      " |  conjugate(...)\n",
      " |      Returns self, the complex conjugate of any int.\n",
      " |  \n",
      " |  from_bytes(...) from builtins.type\n",
      " |      int.from_bytes(bytes, byteorder, *, signed=False) -> int\n",
      " |      \n",
      " |      Return the integer represented by the given array of bytes.\n",
      " |      \n",
      " |      The bytes argument must be a bytes-like object (e.g. bytes or bytearray).\n",
      " |      \n",
      " |      The byteorder argument determines the byte order used to represent the\n",
      " |      integer.  If byteorder is 'big', the most significant byte is at the\n",
      " |      beginning of the byte array.  If byteorder is 'little', the most\n",
      " |      significant byte is at the end of the byte array.  To request the native\n",
      " |      byte order of the host system, use `sys.byteorder' as the byte order value.\n",
      " |      \n",
      " |      The signed keyword-only argument indicates whether two's complement is\n",
      " |      used to represent the integer.\n",
      " |  \n",
      " |  to_bytes(...)\n",
      " |      int.to_bytes(length, byteorder, *, signed=False) -> bytes\n",
      " |      \n",
      " |      Return an array of bytes representing an integer.\n",
      " |      \n",
      " |      The integer is represented using length bytes.  An OverflowError is\n",
      " |      raised if the integer is not representable with the given number of\n",
      " |      bytes.\n",
      " |      \n",
      " |      The byteorder argument determines the byte order used to represent the\n",
      " |      integer.  If byteorder is 'big', the most significant byte is at the\n",
      " |      beginning of the byte array.  If byteorder is 'little', the most\n",
      " |      significant byte is at the end of the byte array.  To request the native\n",
      " |      byte order of the host system, use `sys.byteorder' as the byte order value.\n",
      " |      \n",
      " |      The signed keyword-only argument determines whether two's complement is\n",
      " |      used to represent the integer.  If signed is False and a negative integer\n",
      " |      is given, an OverflowError is raised.\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Data descriptors defined here:\n",
      " |  \n",
      " |  denominator\n",
      " |      the denominator of a rational number in lowest terms\n",
      " |  \n",
      " |  imag\n",
      " |      the imaginary part of a complex number\n",
      " |  \n",
      " |  numerator\n",
      " |      the numerator of a rational number in lowest terms\n",
      " |  \n",
      " |  real\n",
      " |      the real part of a complex number\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(int)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "10"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "int(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "10"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "int(10.9)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-10"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "int(-10.9)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from fractions import Fraction"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "a = Fraction(22, 7)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Fraction(22, 7)"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "int(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can use the second constructor to generate integers (base 10) from strings in any base."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "10"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "int(\"10\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "int(\"101\", 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "int(\"101\", base=2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python uses ``a-z`` for bases from 11 to 36."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that the letters are not case sensitive."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3866"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "int(\"F1A\", base=16)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3866"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "int(\"f1a\", base=16)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Of course, the string must be a valid number in whatever base you specify."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "invalid literal for int() with base 11: 'B1A'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-28-d0cf8657e90a>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'B1A'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mbase\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m11\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mValueError\u001b[0m: invalid literal for int() with base 11: 'B1A'"
     ]
    }
   ],
   "source": [
    "int('B1A', base=11)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "int('B1A', 12)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Base Representations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Built-ins"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "bin(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "oct(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "hex(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note the `0b`, `0o` and `0x` prefixes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can use these in your own strings as well, and they correspond to prefixes used in integer literals as well."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "a = int('1010', 2)\n",
    "b = int('0b1010', 2)\n",
    "c = 0b1010"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "print(a, b, c)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "a = int('f1a', 16)\n",
    "b = int('0xf1a', 16)\n",
    "c = 0xf1a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "print(a, b, c)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For literals, the ``a-z`` characters are not case-sensitive either"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "a = 0xf1a\n",
    "b = 0xF1a\n",
    "c = 0xF1A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "print(a, b, c)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Custom Rebasing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python only provides built-in function to rebase to base 2, 8 and 16.\n",
    "\n",
    "For other bases, you have to provide your own algorithm (or leverage some 3rd party library of your choice)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def from_base10(n, b):\n",
    "    if b < 2:\n",
    "        raise ValueError('Base b must be >= 2')\n",
    "    if n < 0:\n",
    "        raise ValueError('Number n must be >= 0')\n",
    "    if n == 0:\n",
    "        return [0]\n",
    "    digits = []\n",
    "    while n > 0:\n",
    "        # m = n % b\n",
    "        # n = n // b\n",
    "        # which is the same as:\n",
    "        n, m = divmod(n, b)\n",
    "        digits.insert(0, m)\n",
    "    return digits"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from_base10(10, 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from_base10(255, 16)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next we may want to encode the digits into strings using different characters for each digit in the base"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def encode(digits, digit_map):\n",
    "    # we require that digit_map has at least as many\n",
    "    # characters as the max number in digits\n",
    "    if max(digits) >= len(digit_map):\n",
    "        raise ValueError(\"digit_map is not long enough to encode digits\")\n",
    "    \n",
    "    # we'll see this later, but the following would be better:\n",
    "    encoding = ''.join([digit_map[d] for d in digits])\n",
    "    return encoding\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can encode any list of digits:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "encode([1, 0, 1], \"FT\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "encode([1, 10, 11], '0123456789AB')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And we can combine both functions into a single one for easier use:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def rebase_from10(number, base):\n",
    "    digit_map = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n",
    "    if base < 2 or base > 36:\n",
    "        raise ValueError('Invalid base: 2 <= base <= 36')\n",
    "    # we store the sign of number and make it positive\n",
    "    # we'll re-insert the sign at the end\n",
    "    sign = -1 if number < 0 else 1\n",
    "    number *= sign\n",
    "    \n",
    "    digits = from_base10(number, base)\n",
    "    encoding = encode(digits, digit_map)\n",
    "    if sign == -1:\n",
    "        encoding = '-' + encoding\n",
    "    return encoding"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "e = rebase_from10(10, 2)\n",
    "print(e)\n",
    "print(int(e, 2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "e = rebase_from10(-10, 2)\n",
    "print(e)\n",
    "print(int(e, 2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "rebase_from10(131, 11)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "rebase_from10(4095, 16)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "rebase_from10(-4095, 16)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
